#region Usings

using System;
using System.Collections.Generic;
using System.Reflection;
using log4net;
using Newtonsoft.Json;
using Karma.Framework.Core.IoC;
using Karma.Framework.Core.Serialization;
using Karma.Framework.Core.Serialization.Util;
using Karma.Framework.Core.Services.Invoker.Cache;
using Karma.Framework.Core.Utils;
using SerializationConfiguration = Karma.Framework.Core.Serialization.Configuration;

#endregion

namespace Karma.Framework.Core.Services.Invoker.Processor
{
    public class ProcessorCache
    {
        private static IDictionary<string, IDictionary<string, JsonConverter[]>> DeserializationConverters =
            new Dictionary<string, IDictionary<string, JsonConverter[]>>();

        private static ILog LOG = LogManager.GetLogger(typeof (ProcessorCache).Name);

        private static IDictionary<string, IDictionary<string, JsonConverter[]>> SerializationConverters =
            new Dictionary<string, IDictionary<string, JsonConverter[]>>();

        public static void Initialize()
        {
            if (LOG.IsDebugEnabled)
            {
                LOG.Debug("Starting initialization..");
            }
            foreach (var srvkey in InvokerCache.ServiceNames)
            {
                var service = InvokerCache.GetServiceInfo(srvkey);
                var implementationType = IoCUtils.GetImplementationType(service.ServiceType);
                // serialization
                SerializationConverters.Add(srvkey, new Dictionary<string, JsonConverter[]>());
                var classSerializationCoonverters =
                    SerializationUtils.GetConverters<SerializationConvertersAttribute>(implementationType);

                // deserialization
                DeserializationConverters.Add(srvkey, new Dictionary<string, JsonConverter[]>());

                // methods
                foreach (var mtkey in service.Methods.Keys)
                {
                    var method = service.Methods[mtkey].Mi;
                    var implementationMethod = ReflectionUtils.TryGetMethodInfo(implementationType, method.Name,
                                                                                method.GetParameters().Length);

                    // serialzation
                    var converters = new List<JsonConverter>();
                    converters.AddRange(SerializationConfiguration.EnumConverters);
                    converters.AddRange(classSerializationCoonverters);

                    var methodSerializationConverters =
                        SerializationUtils.GetConverters<SerializationConvertersAttribute>(
                            implementationMethod);
                    if (methodSerializationConverters != null && methodSerializationConverters.Length > 0)
                    {
                        converters.AddRange(methodSerializationConverters);
                    }
                    SerializationConverters[srvkey].Add(method.Name + method.GetParameters().Length,
                                                        converters.ToArray());

                    // deserialization
                    DeserializationConverters[srvkey].Add(method.Name + method.GetParameters().Length,
                                                          SerializationUtils.GetConverters
                                                              <DeserializationConvertersAttribute>(implementationMethod));
                }
            }
            if (LOG.IsDebugEnabled)
            {
                LOG.Debug("Initialization finished.");
                LOG.Debug("Configured Serialization converters:");
                foreach (var key in SerializationConverters.Keys)
                {
                    var service = SerializationConverters[key];
                    foreach (var methodkey in service.Keys)
                    {
                        var converters = service[methodkey];
                        LOG.Debug(string.Format("Serialization converters for Method [ {0}.{1} ]: {2}", key, methodkey,
                                                converters.ItemsToString()));
                    }
                }
            }
        }

        public static JsonConverter[] GetDeserializationConverters(Type type, MethodInfo method)
        {
            if (!DeserializationConverters.ContainsKey(type.FullName))
            {
                throw new ArgumentException(string.Format("Convertidores para el Servicio {0} no configurados.",
                                                          type.FullName));
            }
            if (!DeserializationConverters[type.FullName].ContainsKey(method.Name + method.GetParameters().Length))
            {
                throw new ArgumentException(string.Format("Convertidores para el Metodo {0}.{1} no configurados.",
                                                          type.FullName, method.Name));
            }
            return DeserializationConverters[type.FullName][method.Name + method.GetParameters().Length];
        }

        public static JsonConverter[] GetSerializationConverters(Type type, MethodInfo method)
        {
            if (!DeserializationConverters.ContainsKey(type.FullName))
            {
                throw new ArgumentException(string.Format("Convertidores para el Servicio {0} no configurados.",
                                                          type.FullName));
            }
            if (!DeserializationConverters[type.FullName].ContainsKey(method.Name + method.GetParameters().Length))
            {
                throw new ArgumentException(string.Format("Convertidores para el Metodo {0}.{1} no configurados.",
                                                          type.FullName, method.Name));
            }
            return SerializationConverters[type.FullName][method.Name + method.GetParameters().Length];
        }
    }
}